home *** CD-ROM | disk | FTP | other *** search
/ Commodore Free 30 / Commodore_Free_Issue_30_2009_Commodore_Computer_Club.d64 / c part 1.2 < prev    next >
Text File  |  2023-02-26  |  16KB  |  623 lines

  1. u
  2.  
  3.  
  4. Alternative Programming Languages: C
  5. Part 1 By Paul Davis
  6.  
  7.        CONTINUED FROM PART 1.1
  8.  
  9. Formatted output
  10. We have also introduced a new library
  11. function here, printf. The 'f' stands
  12. for 'formatted' & this function gives
  13. us greater control over the layout of
  14. the printed text. The first parameter
  15. is a 'format string'. This is the text
  16. we want to print with placeholders
  17. (marked by a % sign) for the values we
  18. want to display. These values are
  19. passed as extra parameters to the
  20. printf function. The first printf
  21. instruction displays the value of the
  22. 'n' variable. We use a %d placeholder
  23. to print the value of this variable as
  24. a decimal number. The 2nd printf
  25. displays the value of the 'c' variable
  26. & uses the %c placeholder to display
  27. it as a character. The 3rd printf
  28. uses the %s placeholder to display the
  29. contents of the 's' variable as a
  30. string.
  31.  
  32. There is no special format placeholder
  33. for an entire array so we use a loop
  34. to print the values one at a time.
  35. Notice this time we use %5d in the
  36. format. This causes the numbers to be
  37. printed in a 5 character wide field.
  38. Any numbers shorter than 5 digits will
  39. be padded with spaces on the left hand
  40. side to make them line up.
  41.  
  42. There are many other formatting
  43. options provided by the printf
  44. function. I will leave it as an
  45. exercise for the reader to explore
  46. them in more detail. One important
  47. thing to remember though is that
  48. 'printf' is a large, complex function
  49. & will add a considerable amount to
  50. the size of your program. If you need
  51. to keep the size of your program down
  52. you may prefer to use other library
  53. routines for generating output.
  54.  
  55. Finally, notice the '\n' at the end of
  56. each format string. This stands for
  57. 'new line' & moves the cursor down to
  58. the start of the next line.
  59.  
  60. The for loop
  61. The previous example also introduces
  62. C's for loop. The syntax looks strange
  63. at first but it's not too complicated.
  64. The basic form is:
  65.  
  66.   for (initialisation; condition;
  67.    increment)
  68.  
  69. There are three sections in the
  70. brackets, separated by semi-colons.
  71. The first section initialises the
  72. values of any variables needed during
  73. the loop, usually the loop counter.
  74. In our example, we set the value of
  75. 'i', the loop index, to 0. The next
  76. section is the condition. The loop
  77. will run as long as this condition is
  78. true. Note that the condition is
  79. tested at the start of the loop so
  80. it's possible for the body of the loop
  81. to never run at all if the condition
  82. is false the first time round. In our
  83. example, the condition is 'i < 5'.
  84. The loop will keep running while 'i'
  85. is less than 5 & will terminate once
  86. 'i' is 5 or more. The final section of
  87. a for loop is used to increment the
  88. loop variable. Here we have used '++i'
  89. to increment (add 1 to) the value of
  90. 'i'. The for loop here is therefore
  91. roughly equivalent to the following
  92. BASIC loop:
  93.  
  94.   FOR I=0 TO 4:PRINT A(I):NEXT I
  95.  
  96. The console library
  97. While the functions provided by the
  98. 'stdio' library are very useful, they
  99. are general purpose routines designed
  100. for writing & reading streams of data
  101. to & from files. The screen just
  102. happens to be one such type of data
  103. stream. The cc65 compiler provides
  104. another library called 'conio' that is
  105. designed specifically for printing to
  106. the screen & reading from the keyboard
  107. (collectively known as the 'console').
  108. These routines allow extra features
  109. such as moving the cursor to a
  110. specified location on the screen,
  111. changing colours, waiting for a key
  112. press etc. They are also usually
  113. smaller & faster than the equivalent
  114. 'stdio' routines. Let's write a
  115. program to demonstrate some of this
  116. library's features.
  117.  
  118. Close the previous editor window &
  119. create a new file called 'console.c'.
  120. Enter the following program into this
  121. file:
  122. +
  123. #include <conio.h>
  124. !
  125. void colors(int paper, int ink)
  126.  
  127.   bgcolor(paper);
  128.   bordercolor(ink);
  129.   textcolor(ink);
  130.   clrscr();
  131. !
  132.  
  133. void show_title_screen(void)
  134. +
  135.   colors(COLOR_GRAY3, COLOR_GRAY1);
  136.  
  137.   cputsxy(14, 12, "Welcome to C");
  138.  
  139.   cgetc();
  140.   colors(COLOR_BLUE, COLOR_LIGHTBLUE);
  141. !
  142.  
  143. void main(void)
  144. +
  145.   show_title_screen();
  146. !
  147.  
  148. Compile the program with 'cl65
  149. console.c' & run it in VICE. The
  150. program will change the screen colours
  151. to grey & display a message at the
  152. centre of the screen. It then waits
  153. for a key to be pressed before
  154. restoring the default colour scheme.
  155.  
  156. This program introduces a few new
  157. concepts. Let's go through it. The
  158. #include line reads the conio header
  159. file so we can call the functions in
  160. that library.
  161.  
  162. Next, we have created a function
  163. called 'colors' to change the colours
  164. on the screen (I used the American
  165. spelling so the name is consistent
  166. with the names of thelibrary
  167. functions). The function takes two
  168. colour parameters & uses these to
  169. set the background, border & text
  170. colours. It also clears the screen.
  171. Notice how the parameters, just like
  172. variables, must be declared as a
  173. specific type.
  174.  
  175. The 2nd function, 'show_title_screen',
  176. calls our 'colors' function to change
  177. the screen to grey. We can use named
  178. constants for the colours rather than
  179. having to use literal numbers which
  180. makes the program more readable. The
  181. convention for naming constants is to
  182. use all uppercase letters with words
  183. separated by underscores. This makes
  184. it easy to differentiate them from
  185. variables.
  186.  
  187. The function 'cputsxy' is used to
  188. print the message at the centre of the
  189. screen. There are many such functions
  190. in the conio library. Have a look
  191. through the 'conio.h' file (in
  192. c:\cc65\include or
  193. /usr/local/lib/cc65/include) to see
  194. all the functions this library
  195. provides.
  196.  
  197. The 'cgetc' function waits for a key
  198. to be pressed. It actually returns the
  199. ASCII code of that key but we are
  200. ignoring the return value in this
  201. example. Once a key has been pressed,
  202. the colours are restored to the
  203. familiar blue on blue.
  204.  
  205. Notice how the program has been
  206. organised. Each function performs a
  207. small well-defined task, & the 'main'
  208. function does little more than call
  209. our other functions. It's good
  210. practice to build programs up like
  211. this, rather than just dumping
  212. everything into the 'main' function.
  213.  
  214. Also notice that the functions are
  215. defined before the point where they
  216. are first used. Remember that C needs
  217. to know what parameters a function
  218. expects before it can call it. One way
  219. to ensure this in your own program is
  220. to place the function definition
  221. before any code that calls it. C also
  222. provides another, more flexible, way
  223. to do this which we will look at next
  224. time.
  225.  
  226. It would be nice if our program could
  227. calculate the co-ordinates & centre
  228. the text for us. Let's write a
  229. function to do this. First, we need to
  230. know the dimensions of the screen.
  231. Okay, we know that the C64 screen is
  232. 25 lines of 40 columns, but if this
  233. program were run on a C128 in 80
  234. column mode that assumption wouldn't
  235. work. Let's do it the proper way by
  236. asking the conio library for the
  237. dimensions of the screen.
  238.  
  239. First, add this line at the top of the
  240. file under #include <conio.h>:
  241.  
  242. #include <string.h>
  243.  
  244. We need to call a function that is in
  245. the string library so this line reads
  246. the header file for that library. Now
  247. add the following lines above the
  248. 'colors' function:
  249.  
  250. typedef unsigned char byte;
  251.  
  252. byte scr_width, scr_height;
  253.  
  254. void init(void)
  255. +
  256.   screensize(&scr_width, &scr_height);
  257. !
  258.  
  259. void center(char text[], byte y)
  260. +
  261.   cputsxy((scr_width - strlen(text)) /
  262.    2,
  263.           y, text);
  264. !
  265.  
  266. Here we have introduced a number of
  267. new things. First is the 'typedef'
  268. line. We are going to be using a lot
  269. of variables of type 'unsigned char'
  270. which is quite cumbersome to type (and
  271. read). We can use 'typedef' to make a
  272. new type name that is equivalent to
  273. some other type. Here, we are telling
  274. the compiler to allow us to use the
  275. word 'byte' to mean 'unsigned char'
  276. which makes our program much neater.
  277.  
  278. Now, using our new 'byte' type, we
  279. create two global variables to hold
  280. the width & height of the screen. The
  281. variables need to be global so that
  282. the other functions can use them.
  283.  
  284. Next, we create a function that
  285. initialises these variables. using the
  286. 'screensize' function in the conio
  287. library. The significance of the '&'
  288. will be explained in more detail later
  289. when we look at pointers. For now,
  290. suffice it to say that the ampersands
  291. allow the 'screensize' function to
  292. modify the variables passed as
  293. parameters. Remember that a C function
  294. may only return a single value. This
  295. 'modifying the parameters' approach is
  296. one way to get around that limitation.
  297.  
  298. The last new function is 'center'
  299. which takes a text string & a line
  300. number as parameters. The function
  301. then uses 'cputsxy' to print the text
  302. as before, but this time calculates
  303. the x co-ordinate using the length of
  304. the string (obtained using the
  305. 'strlen' library function) & the
  306. screen width.
  307.  
  308. Now we need to change the line that
  309. prints the message to use our new
  310. center function:
  311.  
  312.   center("Welcome to C", scr_height /
  313.    2);
  314.  
  315. And finally, change 'main' to call the
  316. 'init' function at the start of the
  317. program so the screen size is set up
  318. ready for the other functions to use:
  319.  
  320. void main(void)
  321. +
  322.   init();
  323.   show_title_screen();
  324. !
  325.  
  326. Save these changes, re-compile & run
  327. the new program. The result should be
  328. the same as before, but now we have a
  329. general purpose function that can
  330. centre text on any line of the screen.
  331.  
  332. The conio library also supports a
  333. limited form of line drawing using the
  334. Commodore's graphical characters.
  335. Let's use these to put a box around
  336. the edge of the screen. Add the
  337. following function above the
  338. 'colors' function:
  339.  
  340. void box(byte x, byte y, byte w, byte
  341. h)
  342. +
  343.   cputcxy(x, y, CH_ULCORNER);
  344.   chline(w-2);
  345.   cputc(CH_URCORNER);
  346.   cvlinexy(x, y+1, h-2);
  347.   cputc(CH_LLCORNER);
  348.   chline(w-2);
  349.   cputc(CH_LRCORNER);
  350.   cvlinexy(x+w-1, y+1, h-2);
  351. !
  352.  
  353. This function takes as parameters the
  354. co-ordinates of the top left corner of
  355. the box, its width & its height. It
  356. uses a combination of 'cputc' to place
  357. individual corner characters on the
  358. screen & 'chline' and 'cvline' for
  359. drawing horizontal & vertical lines
  360. respectively.
  361.  
  362. Now change the start of the
  363. 'show_title_screen' function to use
  364. our new box drawing capability:
  365.  
  366.   colors(COLOR_GRAY3, COLOR_GRAY1);
  367.   box(0, 0, scr_width, scr_height);
  368.   box(9, 10, scr_width-18,
  369.    scr_height-20);
  370.  
  371. Re-compile & run the console program
  372. again. Now the screen & message have
  373. a box drawn around them. Try
  374. experimenting with these functions to
  375. create your own title screen. How
  376. about changing the colours or having
  377. multiple lines of centred text?
  378.  
  379. Strings
  380. In the previous program we touched
  381. briefly upon the string handling
  382. library. Let's now look at strings in
  383. more detail. As mentioned earlier, a
  384. string is an array of characters. We
  385. can create a string in C by enclosing
  386. it in double quotes & access the
  387. characters in it through the array.
  388. For example, say we created a string
  389. like this:
  390.  
  391.   char s[] = "String";
  392.  
  393. We can access the individual
  394. characters in the array through the
  395. 's' variable. The expression s[0]
  396. would reference the first element in
  397. the array, the letter 'S', the
  398. expression s[1] would reference the
  399. 't' & so on.
  400.  
  401. How do we know when we have reached
  402. the end of the string? C doesn't store
  403. the length of a string, it uses a
  404. terminating 'null' character to mark
  405. the end of it instead. Every function
  406. that manipulates strings needs to
  407. check for this 'null' character
  408. (ASCII code 0).
  409.  
  410. C provides a library of string
  411. functions which we can access by
  412. including the 'string.h' file in our
  413. programs. You have already seen one
  414. such function, called 'strlen' which
  415. calculates the length of a string by
  416. counting the characters until it
  417. reaches the terminating 'null'
  418. character.
  419.  
  420. One slightly awkward feature of the C
  421. language is that the normal assignment
  422. and comparison operators don't work
  423. with strings. The expressions
  424.  'str1 = str2' or 'str1 < str2', for
  425. example, don't work the way you might
  426. expect. Instead, library functions
  427. must be used to copy & compare strings
  428.  
  429. Let's create another program to
  430. demonstrate some of the standard
  431. string library functions that you
  432. will use most often. Create a new
  433. file called 'string.c' & enter the
  434. following code into the file:
  435.  
  436. #include <stdio.h>
  437. #include <string.h>
  438.  
  439. void main(void)
  440. +
  441.   char str[] = "Commodore";
  442.   char copy[20];
  443.  
  444.   printf("str: %s\n", str);
  445.   printf("len: %d\n", strlen(str));
  446.  
  447.   strcpy(copy, str);
  448.   printf("\ncopy: %s\n", copy);
  449.   printf("len: %d\n", strlen(copy));
  450.   printf("cmp: %d\n", strcmp(str,
  451.    copy));
  452.   if (strcmp(str, copy) == 0)
  453.   +
  454.     puts("equal");
  455.   !
  456.   else
  457.   +
  458.     puts("not equal");
  459.   !
  460.  
  461.   strcat(copy, " 64");
  462.   printf("\ncopy: %s\n", copy);
  463.   printf("len: %d\n", strlen(copy));
  464.   printf("cmp: %d\n", strcmp(str,
  465. copy));
  466.   if (strcmp(str, copy) == 0)
  467.   +
  468.     puts("equal");
  469.   !
  470.   else
  471.   +
  472.     puts("not equal");
  473.   !
  474. !
  475.  
  476. As usual, save the file, compile it
  477. using 'cl65 string.c' & run it in
  478. VICE. The program creates a string & a
  479. second array that is used to store a
  480. copy of that string. The 'strlen'
  481. function is used to return the length
  482. the string. The 'strcpy' function
  483. copies the original string into the
  484. 'copy' array.
  485.  
  486. The 'strcmp' function is used to
  487. compare two strings. It returns 0 if
  488. the strings are equal, a number less
  489. than 0 if the 1st string is less than
  490. the 2nd, or a number greater than 0 if
  491. the 1st string is greater than the 2nd
  492. The 'if'statement compares the two
  493. strings & displays 'equal'or 'not
  494. equal' depending on the result. Notice
  495. the use of the '==' operator to check
  496. for equality. In C, the '=' operator
  497. is only used for assigning values to
  498. variables.
  499.  
  500. Finally, the program uses the 'strcat'
  501. function to concatenate extra text to
  502. the end of the copy string. See the
  503. difference this makes to the output of
  504. the 'strlen' & 'strcmp' values.
  505.  
  506. POKE & PEEK
  507.  
  508. The cc65 compiler provides a neat way
  509. of performing POKE & PEEK operations.
  510. Use #include <peekpoke.h> to get these
  511. features:
  512.  
  513.   POKE(address, value);
  514.   PEEK(address);
  515.  
  516. Now, you may be thinking that we can
  517. use these for controlling the graphics
  518. & sound capabilities of the C64.
  519. Indeed we could, but cc65 provides a
  520. better way to help us program the
  521. custom chips by providing a named set
  522. of variables for their registers.
  523. These features are found in the header
  524. file called 'c64.h'.
  525.  
  526. As an example, while we could change
  527. the border colour using a POKE such as
  528. this:
  529.  
  530.   POKE(53280U, COLOR_BLACK);
  531.  
  532. A better way would be to use the
  533. following instruction:
  534.  
  535.   VIC.bordercolor = COLOR_BLACK;
  536.  
  537. This is more readable &, perhaps
  538. surprisingly, is just as efficient as
  539. the equivalent POKE.
  540.  
  541. VIC registers
  542. To demonstrate some of these features,
  543. here's a short program that displays a
  544. sprite on the screen. Create a new
  545. file called 'sprite.c' & enter the
  546. following program into it:
  547.  
  548. #include <string.h>
  549. #include <peekpoke.h>
  550. #include <c64.h>
  551.  
  552. #define SPRITE0_DATA 0x0340
  553. #define SPRITE0_PTR 0x07f8
  554.  
  555. void main(void)
  556. +
  557.   memset((void*)SPRITE0_DATA, 0xff,
  558.    64);
  559.   POKE(SPRITE0_PTR, SPRITE0_DATA /
  560.    64);
  561.   VIC.spr0_color = COLOR_WHITE;
  562.   VIC.spr_hi_x = 0;
  563.   VIC.spr0_x = 100;
  564.   VIC.spr0_y = 100;
  565.   VIC.spr_ena = 1;
  566. !
  567.  
  568. After including all the required
  569. header files, this program uses
  570. #define to create two constants that
  571. are used to tell the VIC chip where
  572. the sprite is stored in memory. The
  573. '0x' prefix on the numbers tells C
  574. they are in hexadecimal.
  575.  
  576. The main function uses 'memset' to
  577. fill the sprite data memory with the
  578. value 0xff (a byte with all bits
  579. turned on). This results in a solid
  580. block image. Next, the pointer for
  581. sprite 0 is set to point to the sprite
  582. data using a POKE. Then we use the
  583. pre-defined variables to set the VIC
  584. registers for sprite colour & position
  585. and finally, make it visible.
  586.  
  587. Try experimenting a little with this
  588. program. How about using a 'for' loop
  589. to move the sprite around the screen?
  590. If you're feeling adventurous, how
  591. about writing a function that takes
  592. the x & y co-ordinates as parameters
  593. & moves the sprite to that position.
  594. The function would have this type
  595. signature:
  596.  
  597.   void move_sprite(int x, int y)
  598.  
  599. The tricky bit is dealing with x
  600. co-ordinates of 256 & above. If x is
  601. less than 256, 'VIC.spr_hi_x' should
  602. be 0 & 'VIC.spr0_x' should be x. But
  603. when x is 256 or more, 'VIC.spr_hi_x'
  604. should be 1 & 'VIC.spr0_x' should be
  605. 'x - 256'.
  606.  
  607. Next time
  608. In the next article we will continue
  609. with the sprite theme & see how to
  610. build your own library of sprite
  611. handling functions. We will also look
  612. at how to integrate assembly language
  613. into your C programs for extra speed.
  614. See you then.
  615.  
  616. Article text & resources are now
  617. available at:
  618.  http://sites.google.com/site/
  619.   develocity/commodore/articles
  620.  
  621. -------------------------
  622.  
  623.